package com.errol.batchprocessor.batchprocessor.advisorimpl.batchsplitter;

import com.renjia.entity.AbstractImportBatch;
import com.renjia.service.generic.middleware.batchprocessor.bo.ThreadPoolStatusBO;
import com.renjia.service.generic.middleware.batchprocessor.payload.AbstractBatchPayload;
import com.renjia.service.generic.middleware.batchprocessor.payload.AbstractPiecePayload;
import com.renjia.service.generic.middleware.batchprocessor.payload.AbstractSinglePayload;
import org.springframework.lang.NonNull;

import java.util.Collections;
import java.util.List;

/**
 * 批处理模型 简单分片算法
 *
 * @author zhang xiao bin
 * @version v1.0
 * @date 2021/03/01
 * @since v5.0.5
 **/
public class ThreadCountBatchSplitter<IE extends AbstractImportBatch, AT extends Enum<?>, BE, SE, BP extends AbstractBatchPayload<IE, AT, BE, SE>, PP extends AbstractPiecePayload<SE, SP>, SP extends AbstractSinglePayload<SE>>
        implements BatchSplitter<IE, AT, BE, SE, BP, PP, SP> {

    /**
     * 根据批次记录数量，按下列判断依次执行：
     * - 100以内，单线程
     * - 1000以内根据批次大小拆分，保证每个分片的长度在 [50, 100] 之间
     * - 1000以上按线程池核心线程数平分
     *
     * @param batchPayload        批次数据
     * @param threadPoolStatus    线程池状态
     * @param batchSplitterHelper 批次添加到批处理器的扩展点
     * @return PP 列表
     */
    @Override
    public List<PP> doSplit(@NonNull BP batchPayload, @NonNull ThreadPoolStatusBO threadPoolStatus, @NonNull BatchSplitterHelper<IE, AT, BE, SE, BP, PP, SP> batchSplitterHelper) {
        int size = batchPayload.getSingleEntityList().size();
        if (size <= 100) {
            // 单线程
            return Collections.singletonList(batchSplitterHelper.newPiecePayload(batchPayload.getSingleEntityList()));
        }
        int threads;
        if (size >= 1000) {
            // 根据核心线程数，平分
            threads = threadPoolStatus.getCorePoolSize();
        } else {
            // 按记录条数，最少 2 个线程，最多 10 个线程；每个线程最少 50 条，最多 100 条
            threads = (int) Math.ceil(size / 100.0);
        }
        return doSplitByPieceCount(size, threads, batchPayload, batchSplitterHelper);
    }
}
